SwapMagic = LibStub("AceAddon-3.0"):NewAddon("SwapMagic", "AceEvent-3.0", "AceConsole-3.0", "AceHook-3.0")

local mod = SwapMagic
local ACD3 = LibStub("AceConfigDialog-3.0")
--local L = LibStub("AceLocale-3.0"):GetLocale("SwapMagic")
local db
local queue = {}
local tt = CreateFrame("GameTooltip", "SMTooltip", UIParent, "GameTooltipTemplate")
tt:SetOwner(UIParent, "ANCHOR_NONE")

local weaponSpeeds = setmetatable({}, {__index = function(t, link)
	tt:SetHyperlink(link)
	for i = 1, tt:NumLines() do
		local l = _G["SMTooltipTextRight" .. i]
		if l then
			local text = l:GetText()
			if text then
				local speed = text:match("(%d.%d+)")
				if speed then
					rawset(t, link, tonumber(speed))
					return rawget(t, link)
				end
			end
		end
	end
	return rawget(t, link)
end})

local options = {
	type="group",
	args = {
		quality = {
			type = "select",
			name = "Quality",
			desc = "Minimum quality of the items",
			get = function() return db.MinQuality end,
			set = function(info, v)
				db.MinQuality = v
			end,
			values = {[0] = "Poor", [1] = "Common", [2] = "Uncommon", [3] = "Rare", [4] = "Epic", [5] = "Legendary", [6] = "Artifact"},
			order = 2
		},
		minSpeed = {
			type = "range",
			name = "Minimum Mainhand Speed",
			get = function() return db.minSpeed end,
			set = function(info, v) db.minSpeed = v end,
			min = 1.0,
			max = 4.0,
			step = 0.1,
			bigStep = 0.1,
			order = 10
		},
		maxSpeed = {
			type = "range",
			name = "Maximum Offhand Weapon Speed",
			get = function() return db.maxSpeed end,
			set = function(info, v) db.maxSpeed = v end,
			min = 1.0,
			max = 4.0,
			step = 0.1,
			bigStep = 0.1,
			order = 11
		}		
	}
}

local defaults = {
	profile = {
		MinQuality = 1,
		minSpeed = 1.0,
		maxSpeed = 4.0
	}
}

function mod:OnInitialize()
	--LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("SwapMagic", options)
	self.db = LibStub("AceDB-3.0"):New("SwapMagicDB", defaults)
	db = self.db.profile
	--local optFrame = ACD3:AddToBlizOptions("SwapMagic")
end

function mod:OnEnable()
	self:Hook("PaperDollFrameItemFlyout_DisplayButton", true)
	self:RawHook("PaperDollFrameItemFlyout_Show", true)
	self:RawHook("GetInventoryItemsForSlot", true)
	self:RawHook("PaperDollFrameItemFlyoutButton_OnClick", true)

	self:HookScript(PaperDollFrameItemFlyout, "OnShow", "PaperDollFrameItemFlyout_OnShow")
	self:HookScript(PaperDollFrameItemFlyout, "OnHide", "PaperDollFrameItemFlyout_OnHide")
	self.PaperDollFrameItemFlyout_OnUpdate = PaperDollFrameItemFlyout:GetScript("OnUpdate")
	PaperDollFrameItemFlyout:SetScript("OnUpdate", nil)

	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PLAYER_ALIVE", "PLAYER_REGEN_ENABLED")
end

function mod:OnDisable()
	self:UnhookAll()
	self:UnregisterEvent("PLAYER_REGEN_ENABLED")
	self:UnregisterEvent("PLAYER_ALIVE")
	PaperDollFrameItemFlyout:SetScript("OnUpdate", self.PaperDollFrameItemFlyout_OnUpdate)
end


function mod:PaperDollFrameItemFlyout_DisplayButton(button, paperDollItemSlot)
	local tex = self:getRarityTexture(button)

	local location = button.location;
	if ( location and location < PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION ) then
		local id, name, textureName, count, durability, maxDurability, invType, locked, start, duration, enable, setTooltip = EquipmentManager_GetItemInfoByLocation(location);
		local _, _, quality = GetItemInfo(id)
		local r, g, b = GetItemQualityColor(quality);
		tex:SetVertexColor(r, g, b)
		tex:Show()
	else
		tex:Hide()
	end
end

do
	local captureInventoryItems = false
	
	local function checkSpeed(link)
		tt:SetHyperlink(link)
	end
	
	local function filterInventoryItems(slot, t)
		for location, itemID in pairs(t) do
			local id, name = EquipmentManager_GetItemInfoByLocation(location)
			local player, bank, bags, _, bag = EquipmentManager_UnpackLocation(location)
			local isOnPlayer = not bags and (slot or 99) <= 19
			if id then
				local itemName, itemLink, itemRarity, itemLevel, itemMinLevel = GetItemInfo(id)
				local validSpeed, speed = true, weaponSpeeds[itemLink]
				if speed and (slot == 16 or slot == 17) then
					validSpeed = (slot == 16 and speed >= db.minSpeed) or (slot == 17 and speed <= db.maxSpeed)
				end
				if not (IsEquippableItem(id) and itemRarity >= db.MinQuality) or isOnPlayer or not validSpeed then
					t[location] = nil
				end
			end
		end
	end

	function mod:GetInventoryItemsForSlot(slot, output)
		self.hooks.GetInventoryItemsForSlot(slot, output)
		if captureInventoryItems then
			filterInventoryItems(slot, output)
		end
	end

	function mod:PaperDollFrameItemFlyout_Show(paperDollItemSlot)
		captureInventoryItems = true
		self.hooks.PaperDollFrameItemFlyout_Show(paperDollItemSlot)
		captureInventoryItems = false
	end
end

do
	local exitedAt = nil
	local function update(self, elapsed)
		if ( not IsModifiedClick("SHOWITEMFLYOUT") ) then
			local button = self.button;
			local focus = GetMouseFocus()
			local parent = focus and focus:GetParent()
			if not ( button and MouseIsOver(button) or MouseIsOver(PaperDollFrameItemFlyout) or parent == PaperDollFrameItemFlyout or parent == PaperDollFrameItemFlyoutButtons) then
				exitedAt = exitedAt or GetTime()
			else
				exitedAt = nil
			end
		end

		if exitedAt and GetTime() - exitedAt > 0.25 then
			self:Hide()
		end
	end

	function mod:PaperDollFrameItemFlyout_OnShow()
		exitedAt = nil
		PaperDollFrameItemFlyout:SetScript("OnUpdate", update)
	end

	function mod:PaperDollFrameItemFlyout_OnHide()
		PaperDollFrameItemFlyout:SetScript("OnUpdate", nil)
	end
end

function mod:getRarityTexture(button)
	if button.rarityTexture then return button.rarityTexture end
	local border = button:CreateTexture(nil, "OVERLAY")
	button.border = border

	border:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
	border:SetVertexColor(0, 255, 0)
	border:SetBlendMode("ADD")
	border:SetAlpha(0.75)
	border:SetPoint("CENTER")
	border:SetWidth(68)
	border:SetHeight(68)
	border:Hide()

	button.rarityTexture = border
	return border
end

local special_slots = {
	[PDFITEMFLYOUT_IGNORESLOT_LOCATION] = true,
	[PDFITEMFLYOUT_UNIGNORESLOT_LOCATION] = true,
	[PDFITEMFLYOUT_PLACEINBAGS_LOCATION] = true
}
function mod:PaperDollFrameItemFlyoutButton_OnClick(button)
	if special_slots[button.location] then
		return self.hooks.PaperDollFrameItemFlyoutButton_OnClick(button)
	end

	local action = EquipmentManager_EquipItemByLocation(button.location, button.id);
	if UnitIsDead("player") or UnitIsGhost("player") or (UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[button.id]) then
		local id = EquipmentManager_GetItemInfoByLocation(button.location)
		local _, link = GetItemInfo(id)
		self:Print("Queued", link or "[Empty Slot]")
		queue[button.id] = action
	else
		EquipmentManager_RunAction(action);
	end
end

function SwapMagic:PLAYER_REGEN_ENABLED()
	for k, v in pairs(queue) do
		EquipmentManager_RunAction(v)
	end
	wipe(queue)
end

